#include "OpenglAppFramework/inc/PlugIn/InstancingPlugIn.h"
#include "OpenglAppFramework/inc/PlugIn/Mesh.h"
#include "OpenglAppFramework/inc/GameObject.h"
#include "OpenglAppFramework/inc/SceneConfig.h"
#include "OpenglAppFramework/inc/Utils.h"
#include <fstream>
#include <iostream>

InstancingPlugIn::InstancingPlugIn(const std::string& name):
    PlugIn(name, PlugInType::Instancing) {
    m_instance_count = 0;
}

InstancingPlugIn::~InstancingPlugIn() {}

int InstancingPlugIn::setConfigData(const nlohmann::json& data) {
    m_data_file_name = data["data_file"];
    return 0;
}

int InstancingPlugIn::init() {
    std::ifstream ifs(m_data_file_name);
    nlohmann::json root = nlohmann::json::parse(ifs, nullptr, true, true);
    m_instance_count = root["data"].size();
    m_mats_data = new glm::mat4[m_instance_count];
    TransformInfo ts_info;
    glm::mat4 model_mat;
    for(uint32_t i = 0; i < m_instance_count; i++) {
        json2TransformInfoWithDefault(root["data"][i]["transform"], ts_info);
        TransformInfo::ToModelMat(ts_info, m_mats_data[i]);
    }CHECK_OPENGL(__FILE__,__LINE__);

    // 加载所有实例用到的model_mats
    glGenBuffers(1, &m_buffer_id);
    glBindBuffer(GL_ARRAY_BUFFER, m_buffer_id);
    glBufferData(GL_ARRAY_BUFFER, m_instance_count * sizeof(glm::mat4), m_mats_data, GL_STATIC_DRAW);
    CHECK_OPENGL(__FILE__,__LINE__);

    // 给顶点设置model_mat属性
    uint32_t attr_idx;
    glBindVertexArray(m_obj->getMesh()->getVAOId());CHECK_OPENGL(__FILE__,__LINE__);

    attr_idx = m_obj->getMesh()->getNextAttrIndex();
    glEnableVertexAttribArray(attr_idx);
    glVertexAttribPointer(attr_idx, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)0);
    glVertexAttribDivisor(attr_idx, 1);

    attr_idx = m_obj->getMesh()->getNextAttrIndex();
    glEnableVertexAttribArray(attr_idx);
    glVertexAttribPointer(attr_idx, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(sizeof(glm::vec4)));
    glVertexAttribDivisor(attr_idx, 1);

    attr_idx = m_obj->getMesh()->getNextAttrIndex();
    glEnableVertexAttribArray(attr_idx);
    glVertexAttribPointer(attr_idx, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(2 * sizeof(glm::vec4)));
    glVertexAttribDivisor(attr_idx, 1);

    attr_idx = m_obj->getMesh()->getNextAttrIndex();
    glEnableVertexAttribArray(attr_idx);
    glVertexAttribPointer(attr_idx, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(3 * sizeof(glm::vec4)));
    glVertexAttribDivisor(attr_idx, 1);

    glBindVertexArray(0);CHECK_OPENGL(__FILE__,__LINE__);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    delete[] m_mats_data;
    return 0;
}

void InstancingPlugIn::destroy() {

}

uint32_t InstancingPlugIn::getInstanceCount() const {
    return m_instance_count;
}
